home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1995 January / macformat-020.iso / Shareware City / Applications / Alpha.5.96 folder / Tcl / UserCode / html.tcl < prev    next >
Encoding:
Text File  |  1994-08-17  |  28.9 KB  |  1,319 lines  |  [TEXT/ALFA]

  1. #================================================================================
  2. # Copyright 1994 by Scott W. Brim.  You may use this software freely, and
  3. # distribute it freely as long as the receiver is not obligated in any 
  4. # way by receiving it.  If you want to distribute it in any other way, contact 
  5. # me at swb1@cornell.edu and we'll see if we can work something out.  Special
  6. # allowances are not unusual.
  7. #================================================================================
  8. #================================================================================
  9. #
  10. # html.tcl:  macros and bindings for HTML documents
  11. #
  12. # Version 0.15
  13. #
  14. # You must have Alpha 5.85 or better to use this distribution, and Alpha 
  15. # 5.92 or better to use its advanced features.  If you don't, get the 
  16. # most recent version from cs.rice.edu under public/Alpha.  For 
  17. # information on installation and customization see HTML Help.  Ideas 
  18. # were originally taken from Marc Andreesen's html.el and Tom Scavo's 
  19. # latex.tcl
  20. #
  21. # If you make improvements to this environment, please share them!
  22. #
  23. #                                     Scott Brim <swb1@cornell.edu>
  24. #
  25. #================================================================================
  26. # Change Log:
  27. #
  28. # Version 0.15, 17 August 1994
  29. #
  30. #    HTML mode is now integrated into the main Alpha distribution.
  31. #    Better documentation all around.
  32. #    Use newModeVar and shadowing; remove requirement that certain flags 
  33. #        be set before or after html.tcl is loaded.
  34. #
  35. # Previous change history available if you're really interested.
  36. #
  37. #================================================================================
  38. #
  39. # To Be Done:
  40. #    Fuller HTML 2.0 implementation.  When it's complete we'll have V1.0.
  41. #    Add better color support with wordBreak and wordBreakPreface?
  42. #    An option, htmlCompactPreferred, for people who prefer compact discursive 
  43. #        lists.
  44. #    Optionally close P, LI, DD, DL.  Put this under the control of an
  45. #        option htmlPreferFull, which will include htmlUseHeadAndBody too.
  46. #    Do something about indentation when filling?
  47. #    Better searching for headers for HTMLMarkFile, e.g. to find headers even
  48. #        when there are IMGs embedded in them.
  49. #    Optional: various length dashes (with Apple-like keybindings); 
  50. #        "id" (not name) in all tags, generated automatically; doctype;
  51. #        strikethrough style, and so on.
  52. #    HTML's menu will have an "HTML 3" in it, which will totally switch the 
  53. #        menu.  In the HTML 3 menu the same position will revert back. 
  54. #        Whether to come up in HTML 2 or HTML 3 mode will depend on a 
  55. #        user-settable variable.
  56. #    When adding title, if one already exists, replace it.
  57. #    A proc to leap from anchor to href and vice versa across multiple 
  58. #        documents.
  59. #    htmlFillParagraph
  60. #    For new disc entries: want compact vs. ordinary (check context)
  61. #    "Balance"-type cmd on cmd-B, to mark text between matching tags.
  62. #    Proc in menu to take selected text & convert chars to char entities as
  63. #        needed.
  64. #    Maybe a submenu under HREF with common URL templates?
  65. #    Proc to force quotation marks in all hrefs.
  66. #    Insert template text in one lump, so that one Undo removes whole thing.
  67. #    Proc for automatic generation of table of contents?
  68. #    Anything marked with "xxx"
  69. #
  70. #================================================================================
  71.  
  72. proc loadHTML {} {
  73.     global HOME modes
  74.     addUserLine "\r\# The following lines install the HyperText Markup Language Mode"
  75.     addUserLine "source \"$HOME:Tcl:UserCode:html.tcl\""
  76.     addUserLine "catch {htmlDummy}"
  77.     addUserLine "enableMenuItem -m install HTML 0\r"
  78.  
  79.     enableMenuItem -m install HTML 0
  80.     set modes [lsort $modes]
  81. }
  82.  
  83. #This icon is present in Alpha 5.86 and beyond.  Check version.
  84. proc htmlAlphaVersion {} {
  85.     regexp {[0-9.]+} [version] vers
  86.     return $vers
  87. }
  88. if [expr [htmlAlphaVersion] < "5.86"] {
  89.     set htmlMenu    "Html"
  90. } else {
  91.     set htmlMenu    "•942"
  92. }
  93.  
  94. set htmlCommentPreString "<!-- "
  95. set htmlCommentSufString " -->"
  96.  
  97. #
  98. # Add mode to mode list.  Requires 5.85 and after.
  99. #
  100. lappend modes HTML
  101. #addMenuItem -m $helpMenu "HTML Help"
  102. set modeMenus(HTML)             htmlMenu
  103. lappend allModeMenus            htmlMenu
  104. lappend modeSuffixes            {*.html} { set winMode HTML }
  105. lappend modeSuffixes            {*.HTML} { set winMode HTML }
  106. set dummyProc(HTML)    htmlDummy
  107.  
  108. newModeVar HTML wordBreakPreface    {[^a-zA-Z0-9_/]}    0
  109. newModeVar HTML wordBreak            {[a-zA-Z0-9_/]+}    0
  110. newModeVar HTML elecLBrace        0    1
  111. newModeVar HTML elecRBrace        0    1
  112. newModeVar HTML electricSemi    0    1
  113. newModeVar HTML wordWrap        1    1
  114. newModeVar HTML prefixString    $htmlCommentPreString    0
  115. newModeVar HTML suffixString    $htmlCommentSufString    0
  116. newModeVar HTML    optionIsMeta    1    1
  117. # Should tags be lower case?
  118. newModeVar HTML htmlUseLowerCase    0    1
  119. # Default number of discursive list entries
  120. newModeVar HTML    htmlDLEntries        3    0
  121. # Should TITLE generate HEAD and BODY?
  122. newModeVar HTML htmlUseHeadAndBody    0    1
  123. # Should •'s be inserted?
  124. newModeVar HTML    htmlUseTabMarks        1    1
  125. # Use opt-cmd or ctl-cmd?  Hack for int'l users.
  126. newModeVar HTML htmlUseCtlCmd        0    1
  127. # Prefer compact or open discursive lists?
  128. newModeVar HTML htmlCompactDiscLists    0    1
  129.  
  130. #
  131. # If user changes these, we need to rebind a lot of keys
  132. #
  133. trace vdelete  htmlUseCtlCmd w htmlTraceUCC
  134. trace variable htmlUseCtlCmd w htmlTraceUCC
  135. proc htmlTraceUCC {nm1 nm2 op} {
  136.     htmlBindKeys
  137.     return $nm1
  138. }
  139.  
  140. trace vdelete  htmlCompactDiscLists w htmlTraceCDL
  141. trace variable htmlCompactDiscLists w htmlTraceCDL
  142. proc htmlTraceCDL {nm1 nm2 op} {
  143.     htmlBindKeys
  144.     return $nm1
  145. }
  146.  
  147.  
  148. #
  149. # color support
  150. #
  151. set HTMLKeyWords {}
  152. regModeKeywords -b $htmlCommentPreString $htmlCommentSufString -m {<} -c red -k blue HTML $HTMLKeyWords
  153. #unset HTMLKeyWords
  154.  
  155. ######################################################################
  156. # Internal Globals
  157. ######################################################################
  158. set htmlLastLink    ""
  159. set htmlCurSel    ""
  160. set htmlIsSel    0
  161.  
  162. proc HTMLMarkFile {} {
  163.     set end [maxPos]
  164.     set pos 0
  165.     set l {}
  166.     set exp {^(<[Aa][^>]*>)?<([Hh][1-6]>[^<]*)</[Hh][1-6]>}
  167.  
  168.     while {![catch {search -f 1 -r 1 -m 0 -i 0 $exp $pos} res]} {
  169.         set start [lindex $res 0]
  170.         set end [lindex $res 1]
  171.         set text [lindex [split [getText $start $end] "<>"] 2]
  172.         set indlevel [getText [expr $start + 2] [expr $start + 3]]
  173.  
  174.         if {$indlevel > 0 && $indlevel < 7} {
  175.             set lab [string range "       " 2 $indlevel]
  176.             append lab $indlevel " " $text
  177.             setNamedMark $lab $start $start $end
  178.         }
  179.  
  180.         set pos $end
  181.     }
  182. }
  183.  
  184. # That's it for hooking into Alpha's mode mechanisms, the rest is just
  185. # straight html stuff.
  186.  
  187. ######################################################################
  188. # General Support Routines
  189. ######################################################################
  190.  
  191. # Snatch the current selection into htmlCurSel, set flag whether there is one
  192. proc htmlGetSel {} {
  193.     global htmlCurSel
  194.     global htmlIsSel
  195.     set htmlCurSel [getSelect]
  196.     set htmlIsSel [string length $htmlCurSel]
  197.     set htmlCurSel [string trim $htmlCurSel]
  198. }
  199.  
  200. # xxx - not done yet
  201. # This thing is supposed to look where the cursor is and remove the 
  202. # outermost tag marks, so automatically converted stuff can be 
  203. # beautified more easily.  I'm not sure how it should behave.  I'm not 
  204. # sure what to do if the selection spans a tag delimiter, for example.
  205. proc htmlUnTag {} {
  206.     global htmlCurSel
  207.     global htmlIsSel
  208.     htmlGetSel
  209.     createTmark htmlUnTagMark [getPos]
  210.     search -f 0 -r 1 "<\[\^<>\]\*</\.\*>"
  211. }
  212.  
  213. ######################################################################
  214. # Tags
  215. ######################################################################
  216.  
  217. # Build a tag boundary.  Decide if upper or lower case.
  218. proc htmlDoTag {text} {
  219.     global htmlUseLowerCase
  220.     insertText "<"
  221.     insertText [expr {${htmlUseLowerCase}?[string tolower $text]:[string toupper $text]}]
  222.     insertText ">"
  223. }
  224.  
  225. # This is used for all simple tags
  226. proc htmlBuildTag {ftype} {
  227.     global htmlUseTabMarks
  228.     global htmlCurSel
  229.     global htmlIsSel
  230.     htmlGetSel
  231.     if {$htmlIsSel} { deleteSelection }
  232.     htmlDoTag $ftype 
  233.     insertText $htmlCurSel
  234.     set currpos [getPos]
  235.     htmlDoTag /$ftype
  236. #    set c [lookAt [getPos]]
  237. #    if {$c != "\ "} {insertText " "} else {forwardChar}
  238.     if {!$htmlIsSel}    {
  239.         if {$htmlUseTabMarks} {insertText "•"}
  240.         goto $currpos
  241.     }
  242. }
  243.  
  244. # This is used for tags that should be on their own lines
  245. proc htmlBuildCRTag {ftype} {
  246.     global htmlUseTabMarks
  247.     global htmlCurSel
  248.     global htmlIsSel
  249.     htmlGetSel
  250.     if {$htmlIsSel} { deleteSelection }
  251.     htmlOpenCR
  252.     htmlDoTag $ftype 
  253.     insertText $htmlCurSel
  254.     set currpos [getPos]
  255.     htmlDoTag /$ftype
  256.     set start [getPos]
  257.     set end [nextLineStart $start]
  258.      set text [getText $start $end]
  259.     carriageReturn
  260.     if {!$htmlIsSel}    {
  261.         if {$htmlUseTabMarks} {insertText "•"}
  262.         goto $currpos
  263.     }
  264. }
  265.  
  266. # This is used for tags that should be surrounded by empty lines
  267. proc htmlBuildCR2Tag {ftype} {
  268.     global htmlUseTabMarks
  269.     global htmlCurSel
  270.     global htmlIsSel
  271.     htmlGetSel
  272.     if {$htmlIsSel} { deleteSelection }
  273. # note the tags are placed at the left margin, ignoring current indent
  274.     htmlOpenCR ; insertText "\n"
  275.     htmlDoTag $ftype 
  276.     carriageReturn
  277.     insertText $htmlCurSel
  278.     set currpos [getPos]
  279.     insertText "\n"
  280.     htmlDoTag /$ftype 
  281.     htmlCloseCR ; carriageReturn
  282.     if {!$htmlIsSel}    {
  283.         if {$htmlUseTabMarks} {insertText "•"}
  284.         goto $currpos
  285.     }
  286. }
  287.  
  288. #
  289. # Here are all the things that use them
  290. #
  291.  
  292. proc htmlTagAddress {} {
  293.     htmlBuildCRTag "ADDRESS"
  294.     message "Address"
  295. }
  296. proc htmlTagBlockquote {} {
  297.     htmlBuildCR2Tag "BLOCKQUOTE"
  298.     message "Blockquote"
  299. }
  300. proc htmlTagBold {} {
  301.     htmlBuildTag "B"
  302.     message "Bold"
  303. }
  304. proc htmlTagCite {} {
  305.     htmlBuildTag "CITE"
  306.     message "Cite"
  307. }
  308. proc htmlTagCode {} {
  309.     htmlBuildTag "CODE"
  310.     message "Code"
  311. }
  312. proc htmlTagDfn {} {
  313.     htmlBuildTag "DFN"
  314.     message "Definition"
  315. }
  316. proc htmlTagEmphasized {} {
  317.     htmlBuildTag "EM"
  318.     message "Emphasized"
  319. }
  320. proc htmlTagFixed {} {
  321.     htmlBuildTag "TT"
  322.     message "Fixed Width"
  323. }
  324. proc htmlTagForm {} {
  325.     htmlBuildCR2Tag "FORM"
  326.     message "Form"
  327. }
  328. proc htmlTagHR {} {
  329.     htmlDoTag "HR"
  330.     message "Horizontal Rule"
  331. }
  332. proc htmlTagItalic {} {
  333.     htmlBuildTag "I"
  334.     message "Italic"
  335. }
  336. proc htmlTagKeyboard {} {
  337.     htmlBuildTag "KBD"
  338.     message "Keyboard"
  339. }
  340. proc htmlTagUnderline {} {
  341.     htmlBuildTag "U"
  342.     message "Underline"
  343. }
  344. proc htmlTagSample {} {
  345.     htmlBuildCRTag "SAMP"
  346.     message "Sample"
  347. }
  348. proc htmlTagStrong {} {
  349.     htmlBuildTag "STRONG"
  350.     message "Strong emphasis"
  351. }
  352. proc htmlTagVarname {} {
  353.     htmlBuildTag "VAR"
  354.     message "Variable name"
  355. }
  356. proc htmlTagPreformatted {} {
  357.     htmlBuildCR2Tag "PRE"
  358.     message "Pre-formatted"
  359. }
  360. proc htmlTagListing {} {
  361.     htmlBuildCR2Tag "LISTING"
  362.     beep
  363.     message "Use 'Preformatted' instead"
  364. }
  365. proc htmlTagXMP {} {
  366.     htmlBuildCR2Tag "XMP"
  367.     beep
  368.     message "Use 'Preformatted' instead"
  369. }
  370.     
  371. proc htmlTagTitle {} {
  372.     global htmlUseTabMarks
  373.     global htmlUseHeadAndBody
  374.     global htmlCurSel
  375.     global htmlIsSel
  376.     if {$htmlUseHeadAndBody} {
  377.         htmlGetSel
  378.         set htmlTTIsSel $htmlIsSel
  379.         if {$htmlTTIsSel} { 
  380.             set htmlTTCurSel $htmlCurSel
  381.             deleteSelection 
  382.         }
  383.         htmlDoTag "HTML"
  384.         htmlBuildCRTag "HEAD"
  385.         htmlBuildCRTag "TITLE"
  386.         if {$htmlTTIsSel} {
  387.             insertText $htmlTTCurSel
  388.         } else {
  389.             createTMark htmlTTMark [getPos]
  390.         }
  391.         htmlTabNext; htmlTabNext
  392.         htmlBuildCR2Tag "BODY"
  393.         if {!$htmlTTIsSel} {
  394.             if {$htmlUseTabMarks} {insertText "•"}
  395.         } else {
  396.             createTMark htmlTTMark [getPos]
  397.         }
  398.         htmlTabNext
  399.         htmlDoTag "/HTML"
  400.         gotoTMark htmlTTMark
  401.         removeTMark htmlTTMark
  402.     } else {
  403.         htmlBuildCRTag "TITLE"
  404.     }
  405.     message "Document title"
  406. }
  407.  
  408. proc htmlTagHeader1 {} {
  409.     htmlBuildCRTag "H1"
  410. }
  411. proc htmlTagHeader2 {} {
  412.     htmlBuildCRTag "H2"
  413. }
  414. proc htmlTagHeader3 {} {
  415.     htmlBuildCRTag "H3"
  416. }
  417. proc htmlTagHeader4 {} {
  418.     htmlBuildCRTag "H4"
  419. }
  420. proc htmlTagHeader5 {} {
  421.     htmlBuildCRTag "H5"
  422. }
  423. proc htmlTagHeader6 {} {
  424.     htmlBuildCRTag "H6"
  425. }
  426.  
  427.  
  428. #
  429. # Lists: Puts <cr>s before and after a list, inserts <li>, leaves the
  430. # insertion point there.  If anything is selected, makes it the first item.
  431. #
  432. proc htmlBuildList {ltype} {
  433.     global htmlUseTabMarks
  434.     global htmlCurSel
  435.     global htmlIsSel
  436.     htmlGetSel
  437.     if {$htmlIsSel} { deleteSelection }
  438.     htmlOpenCR
  439.     htmlDoTag $ltype
  440.     carriageReturn
  441.     htmlDoTag "LI"
  442.     insertText " "
  443.     if {$htmlIsSel} {        # bullet 1 already full
  444.         insertText $htmlCurSel 
  445.         carriageReturn
  446.         htmlDoTag "LI"
  447.         insertText " "
  448.     }
  449.     set currpos [getPos]
  450.     carriageReturn
  451.     htmlDoTag /$ltype
  452.     carriageReturn
  453.     if {!$htmlIsSel && $htmlUseTabMarks} {insertText "•"}
  454.     htmlCloseCR
  455.     if {!$htmlIsSel} {goto $currpos}
  456.  
  457. }
  458.  
  459. # Add list entry.  If there is a selection, make it the entry.
  460. proc htmlTagListEntry {} {
  461.     global htmlCurSel
  462.     global htmlIsSel
  463.     htmlGetSel
  464.     htmlOpenCR
  465.     htmlDoTag "LI"
  466.     insertText " " $htmlCurSel
  467.     message "New entry"
  468. }
  469.  
  470. #
  471. #  Here are all the things that use buildList:
  472. #
  473.  
  474. proc htmlTagBulleted {} {
  475.     htmlBuildList "UL"
  476.     message "Bulleted list"
  477. }
  478. proc htmlTagNumbered {} {
  479.     htmlBuildList "OL"
  480.     message "Numbered list"
  481. }
  482. proc htmlTagMenu {} {
  483.     htmlBuildList "MENU"
  484.     message "Menu"
  485. }
  486. proc htmlTagDirectory {} {
  487.     htmlBuildList "DIR"
  488.     message "Directory"
  489. }
  490.  
  491.  
  492. #
  493. # Discursive Lists (terms and description tags)
  494. #
  495. # The selection becomes the *description* (*not* the term)
  496. #
  497.  
  498. # Build a "compact" glossary
  499. proc htmlDiscCompact {} {
  500.     global htmlUseTabMarks
  501.     global htmlCurSel
  502.     global htmlIsSel
  503.     global htmlDLEntries
  504.     if {![catch {prompt "Compact Discursive List: how many entries?" $htmlDLEntries} \
  505.             numberEntries] && $numberEntries > 0} {
  506.         htmlGetSel
  507.         if {$htmlIsSel} { deleteSelection }
  508.         htmlOpenCR
  509.         htmlDoTag "DL COMPACT"
  510.         carriageReturn
  511.         htmlDoTag "DT"
  512.         insertText " "
  513.         set currpos [getPos]
  514.         insertText "\t"
  515.         htmlDoTag "DD"
  516.         insertText " "
  517.         if {$htmlIsSel} {
  518.             insertText $htmlCurSel
  519.         } else {
  520.             if {$htmlUseTabMarks} {insertText " •"}
  521.         }        
  522.         for {set i 1} {$i < $numberEntries} {incr i} {
  523.             carriageReturn
  524.             htmlDoTag "DT"
  525.             if {$htmlUseTabMarks} {insertText " •"}
  526.             insertText "\t"
  527.             htmlDoTag "DD"
  528.             if {$htmlUseTabMarks} {insertText " •"}
  529.         }
  530.         carriageReturn
  531.         htmlDoTag "/DL"    
  532.         carriageReturn
  533.         if {$htmlUseTabMarks} {insertText "•"}
  534.         htmlCloseCR
  535.         goto $currpos
  536.     }
  537. }
  538.  
  539. # Build a discursive list with more space
  540. proc htmlDiscLong {} {
  541.     global htmlUseTabMarks
  542.     global htmlCurSel
  543.     global htmlIsSel
  544.     global htmlDLEntries
  545.     if {![catch {prompt "Discursive List: how many entries?" $htmlDLEntries} \
  546.             numberEntries] && $numberEntries > 0} {
  547.         htmlGetSel
  548.         if {$htmlIsSel} { deleteSelection }
  549.         htmlOpenCR
  550.         htmlDoTag "DL"
  551.         carriageReturn
  552.         htmlDoTag "DT"
  553.         insertText " "
  554.         set currpos [getPos]
  555.         carriageReturn
  556.         insertText "\t"
  557.         htmlDoTag "DD"
  558.         insertText " "
  559.         if {$htmlIsSel} {
  560.             insertText $htmlCurSel
  561.         } else {
  562.             if {$htmlUseTabMarks} {insertText " •"}
  563.         }        
  564.         for {set i 1} {$i < $numberEntries} {incr i} {
  565.             carriageReturn ; carriageReturn
  566.             backwardChar
  567.             deleteChar
  568.             htmlDoTag "DT"
  569.             if {$htmlUseTabMarks} {insertText " •"}
  570.             carriageReturn
  571.             insertText "\t"
  572.             htmlDoTag "DD"
  573.             if {$htmlUseTabMarks} {insertText " •"}
  574.         }
  575.         carriageReturn
  576.         backwardChar
  577.         deleteChar
  578.         htmlDoTag "/DL"
  579.         carriageReturn
  580.         if {$htmlUseTabMarks} {insertText "•"}
  581.         htmlCloseCR
  582.         goto $currpos
  583.     }
  584. }
  585.  
  586. # Add an individual entry to a discursive list
  587. proc htmlTagDiscEntry {} {
  588.     global htmlUseTabMarks
  589.     global htmlCurSel
  590.     global htmlIsSel
  591.     htmlGetSel
  592.     if {$htmlIsSel} { deleteSelection }
  593.     htmlOpenCR
  594.     htmlDoTag "DT"
  595.     insertText " "
  596.     set currpos [getPos]
  597.     insertText "\t"
  598.     htmlDoTag "DD"
  599.     insertText " "
  600.     if {$htmlIsSel} {
  601.         insertText $htmlCurSel
  602.     } else {
  603.         if {$htmlUseTabMarks} {insertText "•"}
  604.     }
  605.     htmlCloseCR
  606.     goto $currpos
  607. }
  608.  
  609.  
  610. #
  611. # hrefs
  612. #
  613.  
  614. # An href points to an anchor
  615. # If text is selected it is made clickable.
  616. proc htmlTagHref {} {
  617.     global htmlUseTabMarks
  618.     global htmlCurSel
  619.     global htmlIsSel
  620.     global htmlLastLink
  621.     global htmlUseLowerCase
  622.     htmlGetSel
  623.  
  624.     set defref $htmlLastLink
  625.     if {![catch {prompt "HREF to?" $defref} defref]} {
  626.         if {$htmlIsSel} deleteSelection
  627.         if {$htmlUseLowerCase} {
  628.             insertText "<a href=\""
  629.         } else {
  630.             insertText "<A HREF=\""
  631.         }
  632.         insertText $defref "\">" $htmlCurSel
  633.         set currpos [getPos]
  634.         htmlDoTag "/A"
  635.         if {!$htmlIsSel} {
  636.             if {$htmlUseTabMarks} {insertText "•"}
  637.             goto $currpos
  638.         }
  639.         set htmlLastLink $defref
  640.     }
  641. }
  642.  
  643. # An anchor is something which is pointed to by an href.
  644. # If text is selected it is the object of the href.
  645. proc htmlTagAnchor {} {
  646.     global htmlUseTabMarks
  647.     global htmlCurSel
  648.     global htmlIsSel
  649.     global htmlLastLink
  650.     global htmlUseLowerCase
  651.     htmlGetSel
  652.     if {![catch {prompt "Anchor name?" $htmlLastLink} defref]} {
  653.         if {$htmlIsSel} deleteSelection
  654.         if {$htmlUseLowerCase} {
  655.             insertText "<a name=\""
  656.         } else {
  657.             insertText "<A NAME=\""
  658.         }
  659.         insertText $defref "\">" $htmlCurSel        
  660.         set currpos [getPos]
  661.         htmlDoTag "/A"
  662.         if {!$htmlIsSel} {
  663.             if {$htmlUseTabMarks} {insertText "•"}
  664.             goto $currpos
  665.         }
  666.         set htmlLastLink $defref
  667.     }            
  668. }
  669.  
  670. # Inline image href
  671. # If text is selected it is made clickable.
  672. proc htmlTagImg {} {
  673.     global HOME
  674.     global htmlCurSel
  675.     global htmlIsSel
  676.     global htmlUseLowerCase
  677.     htmlGetSel
  678.     if {$htmlIsSel} {
  679.         set defref $htmlCurSel 
  680.     } else {
  681.         set defref ""
  682.     }
  683.     if {![catch {prompt "Image URL?" $defref} defref]} {
  684.         if {$htmlIsSel} deleteSelection
  685.         htmlOpenCR
  686.         if {$htmlUseLowerCase} {
  687.             insertText "<a img src=\""
  688.         } else {
  689.             insertText "<IMG SRC=\""
  690.         }
  691.         insertText $defref "\">"
  692.         htmlCloseCR
  693.         message "Inline image"
  694.     }
  695. }
  696.  
  697.  
  698. ######################################################################
  699.  
  700.  
  701. #
  702. # The following are straight from latex.tcl (thanks!)
  703. #
  704.  
  705. # A boolean function which takes any string and tests to see if
  706. # that string contains all whitespace characters.  Carriage returns 
  707. # are considered whitespace, as are spaces and tabs.
  708. proc htmlIsWhite {anyString} {
  709.     set len [string length $anyString]
  710.     for {set i 0} {$i < $len} {incr i} {
  711.         set c [string index $anyString $i]
  712.         if {($c != "\ ") && ($c != "\t") && ($c != "\r")} then {return 0}
  713.     }
  714.     return 1
  715. }
  716.  
  717. # Insert a carriage return at the insertion point if any
  718. # character preceding the insertion point (on the same line)
  719. # is a non-whitespace character.
  720. proc htmlOpenCR {} {
  721.     set end [getPos]
  722.     set start [lineStart $end]
  723.     set text [getText $start $end]
  724.     if {![htmlIsWhite $text]} carriageReturn
  725. }
  726.  
  727. # Insert a carriage return at the insertion point if any
  728. # character following the insertion point (on the same line)
  729. # is a non-whitespace character.
  730. proc htmlCloseCR {} {
  731.     set start [getPos]
  732.     set end [nextLineStart $start]
  733.     set text [getText $start $end]
  734.     if {![htmlIsWhite $text]} carriageReturn
  735. }
  736.  
  737. # Set up tab stop mechanism.
  738. proc htmlTabGoto {directionIndicator} {
  739.     set searchResult [search -n -f $directionIndicator -m 0 -i 1 -r 0 {•} [getPos]]
  740.     if {[llength $searchResult] == 0} then {
  741.         message "Tab stop not found"
  742.         return 0
  743.     } else {
  744.         goto [lindex $searchResult 0]
  745.         return 1
  746.     }
  747. }
  748. proc htmlTabNext {} {
  749.     if {[htmlTabGoto 1]} {deleteChar}
  750. }
  751. proc htmlTabPrev {} {
  752.     if {[htmlTabGoto 0]} {deleteChar}
  753. }
  754.  
  755. proc htmlTabDeleteAll {} {
  756.     createTMark htmlDelTabMark [getPos]
  757.     goto 0
  758.     set searchpos 0
  759.     while {1} {
  760.         if {$searchpos == [maxPos]} break
  761.         set searchResult [search -f 1 -r 0 -m 0 -n {•} $searchpos]
  762.         if {[llength $searchResult] == 0} break
  763.         deleteText [lindex $searchResult 0] [lindex $searchResult 1]
  764.         set searchpos [getPos]
  765.     }
  766.     message "Tab stops deleted"
  767.     gotoTMark htmlDelTabMark
  768.     removeTMark htmlDelTabMark
  769. }
  770.  
  771. #########################
  772. #
  773. # Procs for HTML special characters
  774. #
  775. #########################
  776.  
  777. # These three are bound to the single keys
  778. proc htmlLt {} {
  779.     global htmlIsSel
  780.     htmlGetSel
  781.     if {$htmlIsSel} { deleteSelection }
  782.     insertText "<\;"
  783. }
  784. proc htmlGt {} {
  785.     global htmlIsSel
  786.     htmlGetSel
  787.     if {$htmlIsSel} { deleteSelection }
  788.     insertText ">\;"
  789. }
  790. proc htmlAmp {} {
  791.     global htmlIsSel
  792.     htmlGetSel
  793.     if {$htmlIsSel} { deleteSelection }
  794.     insertText "&\;"
  795. }
  796.  
  797. # The next three allow you to input the real characters
  798. proc htmlLT {} {
  799.     global htmlIsSel
  800.     htmlGetSel
  801.     if {$htmlIsSel} { deleteSelection }
  802.     insertText "<"
  803. }
  804. proc htmlGT {} {
  805.     global htmlIsSel
  806.     htmlGetSel
  807.     if {$htmlIsSel} { deleteSelection }
  808.     insertText ">"
  809. }
  810. proc htmlAMP {} {
  811.     global htmlIsSel
  812.     htmlGetSel
  813.     if {$htmlIsSel} { deleteSelection }
  814.     insertText "&"
  815. }
  816.  
  817.                        
  818.  
  819. ########################################################################
  820. #
  821. # Menus
  822. #
  823. ########################################################################
  824. # Break
  825. proc htmlBreak {} {
  826.     htmlDoTag "BR"
  827.     carriageReturn
  828. }
  829.  
  830. # CRs before <p>
  831. proc htmlParagraph {} {
  832.     global htmlIsSel
  833.     htmlGetSel
  834.     if {$htmlIsSel} { deleteSelection }
  835.     carriageReturn
  836.     carriageReturn
  837.     htmlDoTag "P"
  838. }
  839.  
  840. # no CRs before <p>
  841. proc htmlParaMark {} {
  842.     global htmlIsSel
  843.     htmlGetSel
  844.     if {$htmlIsSel} { deleteSelection }
  845.     htmlDoTag "P"
  846. }
  847.  
  848. proc htmlComment {} {
  849.     global htmlUseTabMarks
  850.     global htmlCurSel
  851.     global htmlIsSel
  852.     global htmlCommentPreString htmlCommentSufString
  853.  
  854.     htmlGetSel
  855.     if {$htmlIsSel} { deleteSelection }
  856.     htmlOpenCR
  857.     insertText $htmlCommentPreString $htmlCurSel 
  858.     set currpos [getPos]
  859.     insertText $htmlCommentSufString
  860.     htmlCloseCR
  861.     if {!$htmlIsSel}    {
  862.         if {$htmlUseTabMarks} {insertText "•"}
  863.         goto $currpos
  864.     }
  865. }
  866.  
  867. proc htmlMenuItem {menu item} {
  868.     global htmlIsSel
  869.  
  870.     case $menu in {
  871.         {"Html" •942} {
  872.             case $item in {
  873.                 "newParagraph"    {htmlParagraph}
  874.                 "paragraphMark"    {htmlParaMark}
  875.                 "break"            {htmlBreak}
  876.                 "comment"    {htmlComment}
  877.                 "removeTabMarks"    {htmlTabDeleteAll}
  878.             }
  879.         }    
  880.         "Headers" {
  881.             case $item in {
  882.                 "header1"    {htmlTagHeader1}
  883.                 "header2"    {htmlTagHeader2}
  884.                 "header3"    {htmlTagHeader3}
  885.                 "header4"    {htmlTagHeader4}
  886.                 "header5"    {htmlTagHeader5}
  887.                 "header6"    {htmlTagHeader6}
  888.             }
  889.         }
  890.         "Styles"    {
  891.             case $item in {
  892.                 "emphasis"        {htmlTagEmphasized}
  893.                 "strong"        {htmlTagStrong}
  894.                 "bold"            {htmlTagBold}
  895.                 "italic"        {htmlTagItalic}
  896.                 "fixedWidth"    {htmlTagFixed}
  897.                 "keyboard"        {htmlTagKeyboard}
  898.                 "underline"        {htmlTagUnderline}
  899.             }
  900.         }
  901.         "Lists"    {
  902.             case $item in {
  903.                 "addEntry"    {htmlTagListEntry}
  904.                 "bulleted"    {htmlTagBulleted}
  905.                 "numbered"    {htmlTagNumbered}
  906.                 "menu"        {htmlTagMenu}
  907.                 "directory"    {htmlTagDirectory}
  908.             }
  909.         }
  910.         {"Other Tags" "otherTags"}    {
  911.             case $item in {
  912.                 "preformatted"    {htmlTagPreformatted}
  913.                 "title"            {htmlTagTitle}
  914.                 "address"        {htmlTagAddress}
  915.                 "blockquote"    {htmlTagBlockquote}
  916.                 "cite"            {htmlTagCite}
  917.                 "code"            {htmlTagCode}
  918.                 "definition"    {htmlTagDfn}
  919.                 "form"            {htmlTagForm}
  920.                 "horizRule"        {htmlTagHR}
  921.                 "listing"        {htmlTagListing}
  922.                 "sample"        {htmlTagSample}
  923.                 "variable"        {htmlTagVarname}
  924.                 "xMP"            {htmlTagXMP}
  925.             }
  926.         }
  927.         {"discursiveLists" "Discursive Lists"}    {
  928.             case $item in {
  929.                 "addEntry"    {htmlTagDiscEntry}
  930.                 "compactList"    {htmlDiscCompact}
  931.                 "moreSpace" {htmlDiscLong}
  932.             }
  933.         }
  934.         "Hyperlinks"    {
  935.             case $item in {
  936.                 "addHref"    {htmlTagHref}
  937.                 "addAnchor"    {htmlTagAnchor}
  938.                 "addIMG"    {htmlTagImg}
  939.             }
  940.         }
  941.         # Characters: only work by putting a leading space on menu items
  942.         "Characters"    {
  943.             case $item in {
  944.                 "lessthan"    {htmlLt}
  945.                 "greaterthan"    {htmlGt}
  946.                 "ampersand"    {htmlAmp}
  947.                 default        {
  948.                     htmlGetSel
  949.                     if {$htmlIsSel} { deleteSelection }
  950.                     set item [string trim $item]
  951.                     insertText &${item}\;
  952.                 }
  953.             }
  954.         }
  955.     } 
  956.  
  957. }
  958.  
  959. menu -n $htmlMenu -p htmlMenuItem  {
  960.  
  961.     "spellcheckWindow"
  962.     "(-"
  963.     "newParagraph"
  964.     "paragraphMark"
  965.     "break"
  966.     "comment"
  967.     "removeTabMarks"
  968.     "(-"
  969.     
  970.     {menu -n Headers -p htmlMenuItem {
  971.         "header1"
  972.         "header2"
  973.         "header3"
  974.         "header4"
  975.         "header5"
  976.         "header6" 
  977.     }}
  978.  
  979.     {menu -n Styles -p htmlMenuItem {
  980.         "emphasis"
  981.         "strong"
  982.         "bold"
  983.         "italic"
  984.         "fixedWidth"
  985.         "Keyboard"
  986.         "Underline"
  987.     }}    
  988.  
  989.     {menu -n "Lists" -p htmlMenuItem {
  990.         "addEntry"
  991.         "(-"
  992.         "bulleted"
  993.         "numbered"
  994.         "menu"
  995.         "directory" 
  996.     }}
  997.  
  998.     {menu -n "Discursive Lists" -p htmlMenuItem {
  999.         "Add Entry"
  1000.         "(-"
  1001.         "compactList"
  1002.         "moreSpace" 
  1003.     }}
  1004.  
  1005.     {menu -n "Other Tags" -p htmlMenuItem {
  1006.         "preformatted"
  1007.         "title"
  1008.         "address"
  1009.         "blockquote"
  1010.         "cite"
  1011.         "code"
  1012.         "definition"
  1013.         "form"
  1014.         "horizRule"
  1015.         "listing"
  1016.         "sample"
  1017.         "variable"
  1018.         "xMP" 
  1019.     }}
  1020.  
  1021.     {menu -n Hyperlinks -p htmlMenuItem {
  1022.         "addHref"
  1023.         "addAnchor"
  1024.         "addIMG" 
  1025.     }}
  1026.  
  1027.     "(-"
  1028.  
  1029.     {menu -n Characters -p htmlMenuItem {
  1030.         "lessthan"
  1031.         "greaterthan"
  1032.         "ampersand"
  1033.         "(-"
  1034.         " Aacute"
  1035.         " Acirc"
  1036.         " Acircumflex"
  1037.         " Adieresis"
  1038.         " AE"
  1039.         " AElig"
  1040.         " Agrave"
  1041.         " Aring"
  1042.         " Atilde"
  1043.         " Auml"
  1044.         " Ccedil"
  1045.         " Ccedilla"
  1046.         " Delta"
  1047.         " Eacute"
  1048.         " Ecirc"
  1049.         " Ecircumflex"
  1050.         " Edieresis"
  1051.         " Egrave"
  1052.         " Eth"
  1053.         " Euml"
  1054.         " Iacute"
  1055.         " Icirc"
  1056.         " Icircumflex"
  1057.         " Idieresis"
  1058.         " Igrave"
  1059.         " Iuml"
  1060.         " Ntilde"
  1061.         " OE"
  1062.         " Oacute"
  1063.         " Ocirc"
  1064.         " Ocircumflex"
  1065.         " Odieresis"
  1066.         " Ograve"
  1067.         " Omega"
  1068.         " Oslash"
  1069.         " Otilde"
  1070.         " Ouml"
  1071.         " Pi"
  1072.         " Sigma"
  1073.         " Thorn"
  1074.         " Uacute"
  1075.         " Ucirc"
  1076.         " Ucircumflex"
  1077.         " Udieresis"
  1078.         " Ugrave"
  1079.         " Uuml"
  1080.         " Yacute"
  1081.         " Ydieresis"
  1082.         " Ygrave"
  1083.         " aacute"
  1084.         " acirc"
  1085.         " acircumflex"
  1086.         " adieresis"
  1087.         " ae"
  1088.         " aelig"
  1089.         " agrave"
  1090.         " apple"
  1091.         " approxequal"
  1092.         " aring"
  1093.         " atilde"
  1094.         " auml"
  1095.         " breve"
  1096.         " bullet"
  1097.         " caron"
  1098.         " ccedil"
  1099.         " ccedilla"
  1100.         " cedilla"
  1101.         " cent"
  1102.         " circumflex"
  1103.         " copyright"
  1104.         " currency"
  1105.         " dagger"
  1106.         " daggerdbl"
  1107.         " degree"
  1108.         " dieresis"
  1109.         " divide"
  1110.         " dotaccent"
  1111.         " dotlessi"
  1112.         " eacute"
  1113.         " eacute"
  1114.         " ecirc"
  1115.         " ecircumflex"
  1116.         " edieresis"
  1117.         " egrave"
  1118.         " ellipsis"
  1119.         " emdash"
  1120.         " emsp"
  1121.         " endash"
  1122.         " ensp"
  1123.         " eth"
  1124.         " euml"
  1125.         " exclamdown"
  1126.         " fi"
  1127.         " fl"
  1128.         " florin"
  1129.         " fraction"
  1130.         " germandbls"
  1131.         " greaterequal"
  1132.         " guillemotleft"
  1133.         " guillemotright"
  1134.         " guilsinglleft"
  1135.         " guilsinglright"
  1136.         " hellip"
  1137.         " hungarumlaut"
  1138.         " iacute"
  1139.         " icirc"
  1140.         " icircumflex"
  1141.         " idieresis"
  1142.         " igrave"
  1143.         " infinity"
  1144.         " integral"
  1145.         " iuml"
  1146.         " lessequal"
  1147.         " logicalnot"
  1148.         " lozenge"
  1149.         " macron"
  1150.         " mdash"
  1151.         " mu"
  1152.         " nbsp"
  1153.         " ndash"
  1154.         " nobrkspace"
  1155.         " notequal"
  1156.         " ntilde"
  1157.         " oacute"
  1158.         " ocirc"
  1159.         " ocircumflex"
  1160.         " odieresis"
  1161.         " oe"
  1162.         " ogonek"
  1163.         " ograve"
  1164.         " ordfeminine"
  1165.         " ordmasculine"
  1166.         " oslash"
  1167.         " otilde"
  1168.         " ouml"
  1169.         " paragraph"
  1170.         " partialdiff"
  1171.         " periodcentered"
  1172.         " perthousand"
  1173.         " pi"
  1174.         " plusminus"
  1175.         " questiondown"
  1176.         " quot"
  1177.         " quotedblbase"
  1178.         " quotedblleft"
  1179.         " quotedblright"
  1180.         " quoteleft"
  1181.         " quoteright"
  1182.         " quotesinglbase"
  1183.         " radical"
  1184.         " registered"
  1185.         " ring"
  1186.         " section"
  1187.         " shy"
  1188.         " sterling"
  1189.         " szlig"
  1190.         " thorn"
  1191.         " tilde"
  1192.         " trademark"
  1193.         " uacute"
  1194.         " ucirc"
  1195.         " ucircumflex"
  1196.         " udieresis"
  1197.         " ugrave"
  1198.         " uuml"
  1199.         " vellip"
  1200.         " yacute"
  1201.         " ydieresis"
  1202.         " yen"
  1203.         " yuml"
  1204.     }}
  1205.     
  1206. }
  1207.     
  1208. #############################################################################
  1209. #
  1210. # Key Bindings.
  1211. #
  1212. # abbreviations:  <o> = option, <z> = control, <s> = shift, <c> = command
  1213. #
  1214. #############################################################################
  1215.  
  1216. proc htmlBindKeys {} {
  1217.     global htmlCompactDiscLists htmlUseCtlCmd
  1218.     
  1219.     # this is in 5.92 and beyond.
  1220.     catch {deleteModeBindings "HTML"}
  1221.     
  1222.     if (![info exists htmlCompactDiscLists]) {
  1223.         set htmlCompactDiscLists 0
  1224.     }
  1225.     if (![info exists htmlUseCtlCmd]) {
  1226.         set htmlUseCtlCmd 0
  1227.     }
  1228.  
  1229.     if ($htmlCompactDiscLists) {
  1230.         set htmlDLPref htmlDiscCompact
  1231.         set htmlDLAlt  htmlDiscLong
  1232.     } else {
  1233.         set htmlDLPref htmlDiscLong
  1234.         set htmlDLAlt  htmlDiscCompact
  1235.     }    
  1236.     if ($htmlUseCtlCmd) {set htmlBStr "zc"}   else {set htmlBStr "oc"}
  1237.     if ($htmlUseCtlCmd) {set htmlSBStr "szc"} else {set htmlSBStr "soc"}
  1238.  
  1239.     bind 0x30        htmlTabNext        "HTML"
  1240.     bind 0x30    <s> htmlTabPrev    "HTML"
  1241.     
  1242.     # enter & opt-cmd-enter for new-paragraph
  1243.     bind Enter        htmlParagraph    "HTML"
  1244.     bind Enter    <$htmlBStr>    htmlParaMark    "HTML"
  1245.     # (for powerbook 100) xxx - this feels dangerous
  1246.     bind 0x34        htmlParagraph    "HTML"
  1247.     bind 0x34    <$htmlBStr>    htmlParaMark    "HTML"
  1248.     # for those with awkward Enter keys
  1249.     bind 'm'    <z>    htmlParagraph    "HTML"
  1250.     
  1251.     # Comment on semicolon
  1252.     bind 0x29    <$htmlBStr>    htmlComment    "HTML"
  1253.     
  1254.     bind '0'    <$htmlBStr>    htmlTagTitle    "HTML"
  1255.     bind '1'    <$htmlBStr>    htmlTagHeader1    "HTML"
  1256.     bind '1'    <$htmlSBStr>    htmlBreak        "HTML"
  1257.     bind '2'     <$htmlBStr>    htmlTagHeader2    "HTML"
  1258.     bind '3'     <$htmlBStr>    htmlTagHeader3    "HTML"
  1259.     bind '4'     <$htmlBStr>    htmlTagHeader4    "HTML"
  1260.     bind '5'     <$htmlBStr>    htmlTagHeader5    "HTML"
  1261.     bind '6'     <$htmlBStr>    htmlTagHeader6    "HTML"
  1262.     
  1263.     bind 'e'    <$htmlBStr>    htmlTagEmphasized    "HTML"
  1264.     bind 's'    <$htmlBStr>    htmlTagStrong    "HTML"
  1265.     bind 'b'    <$htmlBStr>    htmlTagBold        "HTML"
  1266.     bind 'i'    <$htmlBStr>    htmlTagItalic    "HTML"
  1267.     bind 'f'    <$htmlBStr>    htmlTagFixed    "HTML"
  1268.     bind 'k'    <$htmlBStr>    htmlTagKeyboard    "HTML"
  1269.     
  1270.     bind 'n'    <$htmlBStr>    htmlTagListEntry    "HTML"
  1271.     bind 'u'    <$htmlBStr>    htmlTagBulleted    "HTML"
  1272.     bind 'o'    <$htmlBStr>    htmlTagNumbered    "HTML"
  1273.     bind 'm'    <$htmlBStr>    htmlTagMenu        "HTML"
  1274.     bind 'd'    <$htmlBStr>    htmlTagDirectory    "HTML"
  1275.     
  1276.     bind 'p'    <$htmlBStr>    htmlTagPreformatted    "HTML"
  1277.     bind 't'    <$htmlBStr>    htmlTagTitle    "HTML"
  1278.     bind 'c'    <$htmlBStr>    htmlTagCode        "HTML"
  1279.     bind 'c'    <$htmlSBStr>    htmlTagCite        "HTML"
  1280.     bind 'q'    <$htmlBStr>    htmlTagBlockquote    "HTML"
  1281.     bind 's'    <$htmlSBStr>    htmlTagSample    "HTML"
  1282.     bind 'a'    <$htmlBStr>    htmlTagAddress    "HTML"
  1283.     bind 'v'    <$htmlBStr>    htmlTagVarname    "HTML"
  1284.     bind 'l'    <$htmlBStr>    htmlTagListing    "HTML"
  1285.     bind 'x'    <$htmlBStr>    htmlTagXMP        "HTML"
  1286.     
  1287.     # Discursive List stuff
  1288.     bind 'n'    <$htmlSBStr>    htmlTagDiscEntry    "HTML"
  1289.     bind 'g'    <$htmlBStr>    $htmlDLPref                "HTML"
  1290.     bind 'g'    <$htmlSBStr>    $htmlDLAlt            "HTML"
  1291.     
  1292.     # A "<" is something pointed at.  ">" points to it.
  1293.     bind '.'    <$htmlBStr>    htmlTagHref    "HTML"
  1294.     bind ','    <$htmlBStr>    htmlTagAnchor    "HTML"
  1295.     
  1296.     # An image, right near the usual href
  1297.     bind '/'    <$htmlBStr>    htmlTagImg    "HTML"
  1298.     
  1299.     # "<", ">" and "&" insert their "&" versions.  Shift inserts character.
  1300.     bind ','    <s>        htmlLt    "HTML"
  1301.     bind ','    <$htmlSBStr>    htmlLT    "HTML"
  1302.     bind '.'    <s>        htmlGt    "HTML"
  1303.     bind '.'    <$htmlSBStr>    htmlGT    "HTML"
  1304.     bind '7'    <s>        htmlAmp    "HTML"
  1305.     bind '7'    <$htmlSBStr>    htmlAMP    "HTML"
  1306.     
  1307.     # ISO character entities ...
  1308.     #    I can't put all of them on bindings, and different users want
  1309.     #    different ones.  So skip it.
  1310.     
  1311. }
  1312.  
  1313. # bind the keys based on defaults.  Shadowing will rebind later in 
  1314. # userStartup.tcl.
  1315. htmlBindKeys
  1316.  
  1317. proc htmlDummy {} {}
  1318.